"""
文件服务
负责文件的上传、下载、存储和管理
"""

import os
import shutil
import hashlib
import mimetypes
import logging
from typing import Dict, Any, Optional, List, BinaryIO
from datetime import datetime, timedelta
from pathlib import Path
from werkzeug.utils import secure_filename
from werkzeug.datastructures import FileStorage
from ..models.history import History
from ..utils.file_utils import FileUtils
from ..utils.validation_utils import ValidationUtils

logger = logging.getLogger(__name__)

class FileService:
    """文件服务类"""
    
    def __init__(self, app=None):
        self.app = app
        if app:
            self.upload_folder = app.config.get('UPLOAD_FOLDER', 'storage/uploads')
            self.output_folder = app.config.get('OUTPUT_FOLDER', 'storage/outputs')
            self.temp_folder = app.config.get('TEMP_FOLDER', 'storage/temp')
            self.max_file_size = app.config.get('MAX_CONTENT_LENGTH', 16 * 1024 * 1024)  # 16MB
            self.allowed_extensions = app.config.get('ALLOWED_EXTENSIONS', {'md', 'markdown', 'txt'})
        else:
            self.upload_folder = 'storage/uploads'
            self.output_folder = 'storage/outputs'
            self.temp_folder = 'storage/temp'
            self.max_file_size = 16 * 1024 * 1024
            self.allowed_extensions = {'md', 'markdown', 'txt'}
        
        # 确保目录存在
        self._ensure_directories()
    
    def _ensure_directories(self):
        """确保必要的目录存在"""
        for folder in [self.upload_folder, self.output_folder, self.temp_folder]:
            os.makedirs(folder, exist_ok=True)
    
    def upload_file(self, file: FileStorage, user_id: str) -> Dict[str, Any]:
        """
        上传文件
        
        Args:
            file: 上传的文件对象
            user_id: 用户ID
            
        Returns:
            上传结果
        """
        try:
            # 验证文件
            validation_result = self._validate_upload_file(file)
            if not validation_result['valid']:
                return {
                    'success': False,
                    'error': validation_result['error']
                }
            
            # 生成安全的文件名
            original_filename = file.filename
            secure_name = secure_filename(original_filename)
            
            # 生成唯一文件名
            timestamp = datetime.utcnow().strftime('%Y%m%d_%H%M%S')
            file_hash = self._generate_file_hash(file)
            filename = f"{timestamp}_{file_hash}_{secure_name}"
            
            # 保存文件
            file_path = os.path.join(self.upload_folder, filename)
            file.save(file_path)
            
            # 获取文件信息
            file_size = os.path.getsize(file_path)
            file_type = mimetypes.guess_type(file_path)[0] or 'text/plain'
            
            # 验证文件内容
            content_validation = self._validate_file_content(file_path)
            if not content_validation['valid']:
                # 删除无效文件
                os.remove(file_path)
                return {
                    'success': False,
                    'error': content_validation['error']
                }
            
            # 记录上传历史
            History.record_upload(user_id, None, original_filename, file_size)
            
            logger.info(f"文件上传成功: {filename} ({file_size} bytes)")
            
            return {
                'success': True,
                'filename': filename,
                'original_name': original_filename,
                'file_size': file_size,
                'file_type': file_type,
                'upload_time': datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"文件上传失败: {str(e)}")
            return {
                'success': False,
                'error': f'文件上传失败: {str(e)}'
            }
    
    def download_file(self, task_id: str, user_id: str) -> Dict[str, Any]:
        """
        下载转换后的文件
        
        Args:
            task_id: 任务ID
            user_id: 用户ID
            
        Returns:
            下载信息
        """
        try:
            from ..models.task import Task
            
            # 验证任务
            task = Task.find_by_id(task_id)
            if not task:
                return {'success': False, 'error': '任务不存在'}
            
            if task['user_id'] != user_id:
                return {'success': False, 'error': '无权限下载此文件'}
            
            if task['status'] != Task.STATUS_COMPLETED:
                return {'success': False, 'error': '任务未完成，无法下载'}
            
            # 检查输出文件
            output_file = task.get('output_file')
            if not output_file or not os.path.exists(output_file):
                return {'success': False, 'error': '输出文件不存在'}
            
            # 记录下载历史
            History.record_download(user_id, task_id, task['output_format'], task.get('file_size', 0))
            
            # 生成下载文件名
            original_name = task.get('original_name', 'document')
            name_without_ext = os.path.splitext(original_name)[0]
            download_filename = f"{name_without_ext}.{task['output_format']}"
            
            return {
                'success': True,
                'file_path': output_file,
                'filename': download_filename,
                'file_size': task.get('file_size', 0),
                'content_type': self._get_content_type(task['output_format'])
            }
            
        except Exception as e:
            logger.error(f"文件下载失败 {task_id}: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def get_file_info(self, filename: str) -> Dict[str, Any]:
        """
        获取文件信息
        
        Args:
            filename: 文件名
            
        Returns:
            文件信息
        """
        try:
            file_path = os.path.join(self.upload_folder, filename)
            
            if not os.path.exists(file_path):
                return {'success': False, 'error': '文件不存在'}
            
            stat = os.stat(file_path)
            file_type = mimetypes.guess_type(file_path)[0] or 'text/plain'
            
            return {
                'success': True,
                'filename': filename,
                'file_size': stat.st_size,
                'file_type': file_type,
                'created_time': datetime.fromtimestamp(stat.st_ctime).isoformat(),
                'modified_time': datetime.fromtimestamp(stat.st_mtime).isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取文件信息失败 {filename}: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def delete_file(self, filename: str, folder: str = 'upload') -> Dict[str, Any]:
        """
        删除文件
        
        Args:
            filename: 文件名
            folder: 文件夹类型 ('upload', 'output', 'temp')
            
        Returns:
            删除结果
        """
        try:
            folder_map = {
                'upload': self.upload_folder,
                'output': self.output_folder,
                'temp': self.temp_folder
            }
            
            if folder not in folder_map:
                return {'success': False, 'error': '无效的文件夹类型'}
            
            file_path = os.path.join(folder_map[folder], filename)
            
            if not os.path.exists(file_path):
                return {'success': False, 'error': '文件不存在'}
            
            os.remove(file_path)
            
            logger.info(f"文件删除成功: {file_path}")
            
            return {'success': True, 'message': '文件删除成功'}
            
        except Exception as e:
            logger.error(f"文件删除失败 {filename}: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def cleanup_old_files(self, days: int = 7) -> Dict[str, Any]:
        """
        清理旧文件
        
        Args:
            days: 保留天数
            
        Returns:
            清理结果
        """
        try:
            cutoff_time = datetime.now() - timedelta(days=days)
            cutoff_timestamp = cutoff_time.timestamp()
            
            cleaned_files = {'upload': 0, 'output': 0, 'temp': 0}
            
            # 清理各个文件夹
            for folder_type, folder_path in [
                ('upload', self.upload_folder),
                ('output', self.output_folder),
                ('temp', self.temp_folder)
            ]:
                if not os.path.exists(folder_path):
                    continue
                
                for filename in os.listdir(folder_path):
                    file_path = os.path.join(folder_path, filename)
                    
                    # 跳过目录和.gitkeep文件
                    if os.path.isdir(file_path) or filename == '.gitkeep':
                        continue
                    
                    try:
                        # 检查文件修改时间
                        if os.path.getmtime(file_path) < cutoff_timestamp:
                            os.remove(file_path)
                            cleaned_files[folder_type] += 1
                            logger.debug(f"清理旧文件: {file_path}")
                    except Exception as e:
                        logger.warning(f"清理文件失败 {file_path}: {str(e)}")
            
            total_cleaned = sum(cleaned_files.values())
            logger.info(f"文件清理完成: 共清理 {total_cleaned} 个文件")
            
            return {
                'success': True,
                'cleaned_files': cleaned_files,
                'total_cleaned': total_cleaned
            }
            
        except Exception as e:
            logger.error(f"文件清理失败: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def get_storage_statistics(self) -> Dict[str, Any]:
        """
        获取存储统计信息
        
        Returns:
            存储统计
        """
        try:
            stats = {}
            
            for folder_type, folder_path in [
                ('upload', self.upload_folder),
                ('output', self.output_folder),
                ('temp', self.temp_folder)
            ]:
                if not os.path.exists(folder_path):
                    stats[folder_type] = {'count': 0, 'size': 0}
                    continue
                
                count = 0
                total_size = 0
                
                for filename in os.listdir(folder_path):
                    file_path = os.path.join(folder_path, filename)
                    if os.path.isfile(file_path) and filename != '.gitkeep':
                        count += 1
                        total_size += os.path.getsize(file_path)
                
                stats[folder_type] = {
                    'count': count,
                    'size': total_size,
                    'size_mb': round(total_size / (1024 * 1024), 2)
                }
            
            # 计算总计
            stats['total'] = {
                'count': sum(s['count'] for s in stats.values()),
                'size': sum(s['size'] for s in stats.values()),
                'size_mb': round(sum(s['size'] for s in stats.values()) / (1024 * 1024), 2)
            }
            
            return {'success': True, 'statistics': stats}
            
        except Exception as e:
            logger.error(f"获取存储统计失败: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def _validate_upload_file(self, file: FileStorage) -> Dict[str, Any]:
        """验证上传文件"""
        if not file or not file.filename:
            return {'valid': False, 'error': '未选择文件'}
        
        # 检查文件扩展名
        if not ValidationUtils.validate_file_extension(file.filename, self.allowed_extensions):
            return {
                'valid': False,
                'error': f'不支持的文件类型，仅支持: {", ".join(self.allowed_extensions)}'
            }
        
        # 检查文件大小（通过读取内容长度）
        file.seek(0, 2)  # 移动到文件末尾
        file_size = file.tell()
        file.seek(0)  # 重置到开头
        
        if file_size > self.max_file_size:
            return {
                'valid': False,
                'error': f'文件过大，最大允许 {self.max_file_size // (1024*1024)}MB'
            }
        
        if file_size == 0:
            return {'valid': False, 'error': '文件为空'}
        
        return {'valid': True}
    
    def _validate_file_content(self, file_path: str) -> Dict[str, Any]:
        """验证文件内容"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            # 验证是否为有效的Markdown内容
            if not ValidationUtils.validate_markdown_content(content):
                return {'valid': False, 'error': '文件内容不是有效的Markdown格式'}
            
            return {'valid': True}
            
        except UnicodeDecodeError:
            return {'valid': False, 'error': '文件编码不正确，请使用UTF-8编码'}
        except Exception as e:
            return {'valid': False, 'error': f'文件内容验证失败: {str(e)}'}
    
    def _generate_file_hash(self, file: FileStorage) -> str:
        """生成文件哈希值"""
        file.seek(0)
        content = file.read()
        file.seek(0)  # 重置文件指针
        
        return hashlib.md5(content).hexdigest()[:8]
    
    def _get_content_type(self, output_format: str) -> str:
        """获取输出格式对应的Content-Type"""
        content_types = {
            'pdf': 'application/pdf',
            'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'html': 'text/html',
            'epub': 'application/epub+zip',
            'rtf': 'application/rtf',
            'odt': 'application/vnd.oasis.opendocument.text'
        }
        
        return content_types.get(output_format, 'application/octet-stream')
    
    def create_temp_file(self, content: str, suffix: str = '.tmp') -> str:
        """
        创建临时文件
        
        Args:
            content: 文件内容
            suffix: 文件后缀
            
        Returns:
            临时文件路径
        """
        import tempfile
        
        with tempfile.NamedTemporaryFile(
            mode='w',
            suffix=suffix,
            dir=self.temp_folder,
            delete=False,
            encoding='utf-8'
        ) as temp_file:
            temp_file.write(content)
            return temp_file.name
    
    def copy_file(self, src_path: str, dst_path: str) -> bool:
        """
        复制文件
        
        Args:
            src_path: 源文件路径
            dst_path: 目标文件路径
            
        Returns:
            是否成功
        """
        try:
            # 确保目标目录存在
            os.makedirs(os.path.dirname(dst_path), exist_ok=True)
            
            shutil.copy2(src_path, dst_path)
            return True
            
        except Exception as e:
            logger.error(f"文件复制失败 {src_path} -> {dst_path}: {str(e)}")
            return False
    
    def move_file(self, src_path: str, dst_path: str) -> bool:
        """
        移动文件
        
        Args:
            src_path: 源文件路径
            dst_path: 目标文件路径
            
        Returns:
            是否成功
        """
        try:
            # 确保目标目录存在
            os.makedirs(os.path.dirname(dst_path), exist_ok=True)
            
            shutil.move(src_path, dst_path)
            return True
            
        except Exception as e:
            logger.error(f"文件移动失败 {src_path} -> {dst_path}: {str(e)}")
            return False